#include <stdint.h>

static const uint16_t crc12tab[256] = {
  0x0000,0x0a0b,0x0a15,0x001e,0x0a29,0x0022,0x003c,0x0a37,
  0x0a51,0x005a,0x0044,0x0a4f,0x0078,0x0a73,0x0a6d,0x0066,
  0x0aa1,0x00aa,0x00b4,0x0abf,0x0088,0x0a83,0x0a9d,0x0096,
  0x00f0,0x0afb,0x0ae5,0x00ee,0x0ad9,0x00d2,0x00cc,0x0ac7,
  0x0b41,0x014a,0x0154,0x0b5f,0x0168,0x0b63,0x0b7d,0x0176,
  0x0110,0x0b1b,0x0b05,0x010e,0x0b39,0x0132,0x012c,0x0b27,
  0x01e0,0x0beb,0x0bf5,0x01fe,0x0bc9,0x01c2,0x01dc,0x0bd7,
  0x0bb1,0x01ba,0x01a4,0x0baf,0x0198,0x0b93,0x0b8d,0x0186,
  0x0881,0x028a,0x0294,0x089f,0x02a8,0x08a3,0x08bd,0x02b6,
  0x02d0,0x08db,0x08c5,0x02ce,0x08f9,0x02f2,0x02ec,0x08e7,
  0x0220,0x082b,0x0835,0x023e,0x0809,0x0202,0x021c,0x0817,
  0x0871,0x027a,0x0264,0x086f,0x0258,0x0853,0x084d,0x0246,
  0x03c0,0x09cb,0x09d5,0x03de,0x09e9,0x03e2,0x03fc,0x09f7,
  0x0991,0x039a,0x0384,0x098f,0x03b8,0x09b3,0x09ad,0x03a6,
  0x0961,0x036a,0x0374,0x097f,0x0348,0x0943,0x095d,0x0356,
  0x0330,0x093b,0x0925,0x032e,0x0919,0x0312,0x030c,0x0907,
  0x0f01,0x050a,0x0514,0x0f1f,0x0528,0x0f23,0x0f3d,0x0536,
  0x0550,0x0f5b,0x0f45,0x054e,0x0f79,0x0572,0x056c,0x0f67,
  0x05a0,0x0fab,0x0fb5,0x05be,0x0f89,0x0582,0x059c,0x0f97,
  0x0ff1,0x05fa,0x05e4,0x0fef,0x05d8,0x0fd3,0x0fcd,0x05c6,
  0x0440,0x0e4b,0x0e55,0x045e,0x0e69,0x0462,0x047c,0x0e77,
  0x0e11,0x041a,0x0404,0x0e0f,0x0438,0x0e33,0x0e2d,0x0426,
  0x0ee1,0x04ea,0x04f4,0x0eff,0x04c8,0x0ec3,0x0edd,0x04d6,
  0x04b0,0x0ebb,0x0ea5,0x04ae,0x0e99,0x0492,0x048c,0x0e87,
  0x0780,0x0d8b,0x0d95,0x079e,0x0da9,0x07a2,0x07bc,0x0db7,
  0x0dd1,0x07da,0x07c4,0x0dcf,0x07f8,0x0df3,0x0ded,0x07e6,
  0x0d21,0x072a,0x0734,0x0d3f,0x0708,0x0d03,0x0d1d,0x0716,
  0x0770,0x0d7b,0x0d65,0x076e,0x0d59,0x0752,0x074c,0x0d47,
  0x0cc1,0x06ca,0x06d4,0x0cdf,0x06e8,0x0ce3,0x0cfd,0x06f6,
  0x0690,0x0c9b,0x0c85,0x068e,0x0cb9,0x06b2,0x06ac,0x0ca7,
  0x0660,0x0c6b,0x0c75,0x067e,0x0c49,0x0642,0x065c,0x0c57,
  0x0c31,0x063a,0x0624,0x0c2f,0x0618,0x0c13,0x0c0d,0x0606
};

uint16_t crc12(const char *buf, unsigned int len) {
  uint16_t crc = 0x0;
  while (len--) {
    crc = ((crc >> 8) | (*buf++ << (4))) ^ crc12tab[ crc & 0xff];
  }
  crc = (crc >> 8) ^ crc12tab[crc & 0xff];
  return crc & 0x0FFF;
}
